/*
 * Reaction.h
 *
 *  Created on: 23 May 2011
 *      Author: allan
 */

#ifndef REACTION_H_
#define REACTION_H_

// C++ includes
#include <iostream>
#include <functional>
#include <memory>
using namespace std;

// Eigen includes
#include <Eigen/Core>
using namespace Eigen;

// GeoReact includes
#include "EquilibriumConstant.h"
#include "Kinetics/Kinetics.h"
#include "SpeciesMap.h"
#include "Types.h"

struct ReactionSpecies 
{
	/// The name of the species participating in the reaction
	string name; 
	
	/// The index of the species participating in the reaction
	Index index;
	
	/// The stoichiometry of the species participating in the reaction
	double stoichiometry; 
};

class ReactionEquation
{
public:
	ReactionEquation(const SpeciesMap& speciesMap);
	
	void
	Set(const string& equation);
	
	void
	Set(const string& reactant, const vector<string>& products, const vector<double>& stoichiometries);
	
	const ReactionSpecies&
	GetReactant() const;
	
	const vector<ReactionSpecies>&
	GetProducts() const;
	
private:
	/// The species map object (to be initialized in the constructor)
	const SpeciesMap& speciesMap;
	
	/// The reactant of the reaction
	ReactionSpecies reactant;
	
	/// The products of the reaction
	vector<ReactionSpecies> products;
};

class Reaction
{
public:
	Reaction();
	
	Reaction(const ReactionEquation& equation);
	
	Reaction(const ReactionEquation& equation, const EquilibriumConstant& K);
	
	void
	SetEquilibriumConstant(const EquilibriumConstant& K);
	
	template<class KineticsType> void
	SetKinectics(const KineticsType& kinetics);
	
	const ReactionSpecies&
	GetReactant() const;
	
	const vector<ReactionSpecies>&
	GetProducts() const;
	
	const EquilibriumConstant&
	GetEquilibriumConstant() const;
	
	const double
	ReactionQuotient(const VectorXd& a) const;
	
	const double
	MassRate(double T, double P, const VectorXd& n, const VectorXd& a) const;
	
private:
	/// The reactant of the reaction
	ReactionSpecies reactant;
	
	/// The products of the reaction
	vector<ReactionSpecies> products;
	
	/// The equilibrium constant object of the reaction
	EquilibriumConstant K;
	
	/// The kinetics instance responsible to compute the rates of the reaction
	std::shared_ptr<const Kinetics> kinetics;
};

template<class KineticsType>
void Reaction::SetKinectics(const KineticsType& kinetics)
{ this->kinetics = std::shared_ptr<const Kinetics>(new KineticsType(kinetics)); }

ostream& operator<<(ostream& out, const Reaction& reaction);

#endif /* REACTION_H_ */
